﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class FingerInput : MonoBehaviour
{
	public delegate void Callback();
	public delegate void CallbackVector3(Vector3 i_Vector3);
	public delegate void CallbackEvent(CommonInput.InputEvent i_Event);
	public delegate void MouseDirCallback(bool i_CW);
	
	public Callback MouseTap;
	public Callback MouseDown;
	public Callback MouseUp;
	public Callback MousePressed;
	public CallbackVector3 MouseDrag;
	public Callback MouseDragStart;
	public Callback MouseDragStop;
	public Callback MouseSwipe;
	public CallbackEvent MouseStroke;
	public Callback DoubleTap;

	public LockInput.LockType m_LockType;
	
	// INPUT VALUES
	private float m_TapTime = 0.2f;
	private float m_DoubleTapTime = 0.4f;
	private float m_SwipeSqrSpeed = 100f;
	
	// OTHER VALUES
	private bool m_CanDrag = false;
	private bool m_MouseIsDown;
	private bool m_MouseStartDrag;
	private bool m_CheckForCircle;
	private bool m_CheckForSwipe;
	private bool m_CheckForDoubleTap;
	private bool m_MouseDownFlag;
	private float m_MousePressed;
	private float m_AverageDelta;
	private float m_DoubleTapTimer;
	private Vector3 m_TempVector;
	private Vector3 m_CircleCenter;
	private CommonInput.InputEvent m_Event;
	
	private List<int> m_CircleQuadrants;
	
	private void Start()
	{
		if (CommonInput.Instance == null)
		{
			GameObject input = new GameObject();
			input.AddComponent<CommonInput>();
			input.name = "Common Input";
		}
	}

	private void Update()
	{
		if (m_MouseIsDown && (Time.time - m_MousePressed > m_TapTime || m_Event.m_Delta.sqrMagnitude > (Screen.width / 20f)))
		{
			m_CanDrag = true;
			m_CheckForDoubleTap = false;
		}
		
		if (m_MouseIsDown && MousePressed != null)
		{
			MousePressed();
		}
		
		if (m_CheckForSwipe)
		{
			OnMouseSwipe();
		}

		if (m_MouseDownFlag)
		{
			m_MouseDownFlag = false;
			TriggerMouseDown();
		}
	}

	private void FixedUpdate()
	{
		if (m_MouseIsDown && m_CanDrag)
		{
			if(!m_MouseStartDrag)
			{
				m_MouseStartDrag = true;
				if (MouseDragStart != null)
				{
					MouseDragStart();
				}
			}
			OnMouseStroke();
			
			if (MouseDrag != null)
			{
				MouseDrag(m_Event.m_Delta);
			}
		}

		m_DoubleTapTimer += Time.fixedDeltaTime;
		if (m_DoubleTapTimer > m_DoubleTapTime)
		{
			m_CheckForDoubleTap = false;
		}
	}
	
	// Mouse button is clicked over object, called by CommonInput
	private void OnFingerDown(CommonInput.InputEvent i_Event)
	{
		m_Event = i_Event;

		if (LockInput.AvailableTo(m_LockType))
		{
			m_MouseDownFlag = true;
		}
	}

	// Triggered by mouse down flag
	private void TriggerMouseDown()
	{
		if (LockInput.AvailableTo(m_LockType))
		{
			m_MouseIsDown = true;
			m_CanDrag = false;
			m_MousePressed = Time.time;
			m_CheckForSwipe = true;

			if (MouseDown != null)
			{
				MouseDown();
			}
		}
	}

	// Mouse button is up anywhere on screen, called by CommonInput
	private void OnFingerUp(CommonInput.InputEvent i_Event)
	{
		m_MouseIsDown = false;

		if (LockInput.AvailableTo(m_LockType))
		{
			if (m_CanDrag)
			{
				m_CanDrag = false;
				m_MouseStartDrag = false;
				if (MouseDragStop != null)
				{
					MouseDragStop();
				}
			}

			OnMouseSwipeUp();

			if (MouseUp != null)
			{
				MouseUp();
			}
		}

		m_Event = null;
	}

	// Mouse button is up on same object as it was down, called by CommonInput
	private void OnFingerUpAsButton(CommonInput.InputEvent i_Event)
	{
		if (LockInput.AvailableTo(m_LockType))
		{
			if (!m_CanDrag)
			{
				if (!m_CheckForDoubleTap)
				{
					OnMouseTap();

					StartDoubleTap();
				}
				else
				{
					EndDoubleTap();
				}
			}
		}
	}
	
	// A click of the mouse
	private void OnMouseTap()
	{
		//Debug.Log(this + " OnMouseTap");
		if (MouseTap != null)
		{
			MouseTap();
		}
	}

	private void StartDoubleTap()
	{
		m_CheckForDoubleTap = true;
		m_DoubleTapTimer = 0f;
	}

	private void EndDoubleTap()
	{
		if (m_DoubleTapTimer <= m_DoubleTapTime)
		{
			if (DoubleTap != null)
			{
				DoubleTap();
			}
		}

		m_CheckForDoubleTap = false;
	}
	
	// Mouse down & moving over object
	private void OnMouseStroke()
	{
		if (m_Event.m_ChangeDirection)
		{
			if (MouseStroke != null)
			{
				MouseStroke(m_Event);
			}
		}
	}
	
	// High mouse speed on up
	private void OnMouseSwipe()
	{
		m_AverageDelta += m_Event.m_Delta.sqrMagnitude;
		m_AverageDelta /= 2f;
	}
	
	private void OnMouseSwipeUp()
	{
		if (m_AverageDelta >= m_SwipeSqrSpeed)
		{
			if (MouseSwipe != null)
			{
				MouseSwipe();
			}
		}
		
		m_CheckForSwipe = false;
	}
}
